﻿/*
* MacroService 功能序列：
* 1. 录制：StartRecording - Recording... - StartSnaping - Snaping - StopRecoding
* 2. 播放：StartPlaying - Playing... - StartSnaping - Snaping - Checking
* 3. 同步：TODO
*/

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using System.Windows.Input;
using zy_simu.Views;

namespace zy_simu.Data
{
    internal class MacroService
    {
        public bool IsRecording = false;    // 是否宏录制中

        private int cmd_delay_param = 0;    // cmd delay 的参数计数
        private byte key = 0;               // key 状态

        public string mac_value { get; set; } = "";       // 宏记录

        private long last_time = 0;
        private uint[] k_last_state;
        private DeviceSnap dev_snap { get; set; } = default!;
        private DisplayPanel DispPanel { get; set; } = default!;
        private HardwarePanel HWPanel { get; set; } = default!;
        private SimuCfg emu_cfg = default!;
        private Task excete_task;
        // 录制延时动作
        private string RecordDelay()
        {
            // 记录时间差, 超过50ms才记录
            long span = (DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond) - last_time;
            if (span > 50)
            {
                last_time = DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond;
                return $"延时[{span}]; ";
            }
            return "";
        }
        // 记录key动作
        private string RecordKey()
        {
            //if (dev_snap.key_state.Length != k_last_state.Length) return "";// 保护一下
            //System.Text.StringBuilder str = new(100);
            //// 记录动作
            //for (int i = 0; i < dev_snap.key_state.Length; i++)
            //{
            //    if ((k_last_state[i] & 0x80000000) != (dev_snap.key_state[i] & 0x80000000))
            //    {
            //        // 记录key变化
            //        if ((dev_snap.key_state[i] & 0x80000000) != 0)
            //            str.Append($"按下[{dev_snap?.keys_def[i]}]; ");
            //        else
            //            str.Append($"松开[{dev_snap?.keys_def[i]}]; ");
            //        k_last_state[i] = dev_snap.key_state[i];
            //    }
            //}
            //return str.ToString();
            return "";
        }
        // 记录箱体温度
        private bool RecordBoxTem(float tem)
        {
            // 记录动作
            mac_value += $"箱温[{tem}]; ";
            return true;
        }
        // 记录HW/GPIO相关变动
        private bool ntc1;      // last NTC状态
        private bool door1;     // last door状态
        private bool sys_switch;     // last 本地开关状态
        private float box_tem;     // last 箱体温度
        private string RecordHW()
        {
            bool ret = false;
            System.Text.StringBuilder str = new(100);
            //ret = dev_snap.ReadGPIO(dev_snap.gpio_tb.det_door1);
            //if (ret != door1)
            //{
            //    door1 = ret;
            //    str.Append($"门1[{(door1 ? "开" : "关")}]; ");
            //}
            //ret = dev_snap.ReadGPIO(dev_snap.gpio_tb.det_sys_switch);
            //if (ret != sys_switch)
            //{
            //    sys_switch = ret;
            //    str.Append($"系统开关[{(sys_switch ? 1 : 0)}]; ");
            //}
            //ret = ((dev_snap.st.alarm & (byte)(ZqAlarmFlag.ZQ_ALARM_SENSOR)) == 0);
            //if (ret != ntc1)
            //{
            //    ntc1 = ret;
            //    str.Append($"NTC1[{(ntc1 ? 0 : 1)}]; ");
            //}
            return str.ToString();
        }




        public MacroService()
        {
            this.dev_snap = null;
        }
        public void Init(DeviceSnap snap, DisplayPanel DispPanel, HardwarePanel HWPanel, SimuCfg emu_cfg)
        {
            //this.dev_snap = snap;
            //this.DispPanel = DispPanel;
            //this.HWPanel = HWPanel;
            //this.emu_cfg = emu_cfg;
            //k_last_state = new uint[dev_snap.keys_def.Length];
        }

        private bool IsExcuting = false;
        public bool StartRecording()
        {
            if (IsRecording || IsExcuting) return false;           // 已经记录中/执行中
            //IsRecording = true;
            //snaping_ms = -1;
            //snaping_timer = 0;
            //snaping_dict.Clear();

            //// 记录一些外设初始状态
            //door1 = dev_snap.ReadGPIO(dev_snap.gpio_tb.det_door1);
            //sys_switch = dev_snap.ReadGPIO(dev_snap.gpio_tb.det_sys_switch);
            //ntc1 = ((dev_snap.st.alarm & (byte)(ZqAlarmFlag.ZQ_ALARM_SENSOR)) == 0);

            //mac_value = "记录; ";
            //last_time = DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond;
            return true;
        }
        public bool StopRecording()
        {
            // if (cmds_idx >= 0) return false;         // 执行中，不能动作
            IsRecording = false;
            last_time = DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond;
            mac_value += "\n";
            return true;
        }
        public bool Recording()
        {
            if (!IsRecording) return false;      // 未激活状态不记录
            //string str;
            //if (snaping_ms >= 0)      // snaping 状态中, 停止记录宏
            //{
            //    str = Snaping();
            //    if (str.Length > 0)
            //        mac_value += str;
            //    return true;
            //}

            //str = RecordHW();
            //str += RecordKey();
            //if (str.Length > 0)
            //    mac_value = mac_value + RecordDelay() + str;
            return true;
        }
        public void Snap()
        { /*                  
            if (mac_value.Length == 0) mac_value += "快照; ";
            else mac_value = mac_value + RecordDelay() + "\n快照; ";
            //Dictionary<string, string> dict_disp = DispPanel.Snap(); // TODOOO 应该dev_snap的功能
            Dictionary<string, string> dict_hw = HWPanel.Snap();
            StringBuilder sb = new StringBuilder(1024);
            foreach(KeyValuePair<string, string> kvp in dict_disp)
                sb.Append($"{kvp.Key}[{kvp.Value}]; ");
            foreach (KeyValuePair<string, string> kvp in dict_hw)
                sb.Append($"{kvp.Key}[{kvp.Value}]; ");
            sb.Append("\n");
            mac_value += sb;
            //return true;
         */
        }

        private int snaping_ms = -1;
        private int snaping_timer = 0;
        private Dictionary<string, string> snaping_dict = new();
        private string GetSnapingResult()
        {
            if (snaping_ms < 0) return "";
            StringBuilder sb = new StringBuilder(2048);
            // 多周期采样，计算闪烁的情景
            if (snaping_ms > dev_snap.TASK_PERIOD)
            {
                // 多周期采样，计算闪烁的情景
                foreach (KeyValuePair<string, string> kvp in snaping_dict)
                {
                    string[] items = kvp.Value.Split(',', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries);
                    // 数字最复杂，有类似于HA,HA,15,15这样的变化闪速, 目前只是初步判断snaping期间内几个值都出现就算对 -- TODO 不是很严谨
                    if (kvp.Key == "数显")
                    {
                        // 去除重复重新合并
                        HashSet<string> list = new();
                        for (int i = 0; i < items.Length; i++) list.Add(items[i]);
                        snaping_dict[kvp.Key] = string.Join(",", list);
                        continue;
                    }
                    // 其它闪速通过简单统计值有多少次变化，来判断闪烁频率 -- TODO 不是很严谨
                    string str = items[0];
                    int k = 0;
                    for (int i = 0; i < items.Length; i++)
                    {
                        if (str != items[i])
                        {
                            k++;
                            str = items[i];
                        }
                    }
                    int hz = (snaping_ms / 1000) * 2; // (snaping_ms / 1000) * 2 -- 1Hz变化次数
                    int delta = (snaping_ms / 1000) * 2 - k;
                    if ((hz - k) <= 2 && (hz - k) >= -2) // 和k比较要小于一个范围判断为1hz闪烁
                        snaping_dict[kvp.Key] = "闪1";
                    else if ((2 * hz - k) <= 2 && (2 * hz - k) >= -2) // 和k比较要小于一个范围判断为0.5hz闪烁
                        snaping_dict[kvp.Key] = "闪.5";
                }
            }

            foreach (KeyValuePair<string, string> kvp in snaping_dict)
                sb.Append($"{kvp.Key}[{kvp.Value}]; ");
            return sb.ToString();
        }

        private string Snaping()
        {
            Dictionary<string, string> dict;
            //Dictionary<string, string> dict = DispPanel.Snap(); // TODOOO 应该dev_snap的功能
            //foreach (KeyValuePair<string, string> kvp in dict)
            //{
            //    string item_str = snaping_dict.GetValueOrDefault(kvp.Key, "");
            //    if (item_str == "") // 首次加入该item
            //    {
            //        snaping_dict[kvp.Key] = kvp.Value;
            //        continue;
            //    }
            //    string[] items = item_str.Split(',', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries); // StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries， 有空白字符表示数字不亮，不能裁剪
            //    if (items[^1] != kvp.Value)
            //        snaping_dict[kvp.Key] += $", {kvp.Value}";
            //}
            dict = HWPanel.Snap();
            foreach (KeyValuePair<string, string> kvp in dict)
            {
                string item_str = snaping_dict.GetValueOrDefault(kvp.Key, "");
                if (item_str == "") // 首次加入该item
                {
                    snaping_dict[kvp.Key] = kvp.Value;
                    continue;
                }
                string[] items = item_str.Split(',', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries);
                if (items[^1] != kvp.Value)
                    snaping_dict[kvp.Key] += $", {kvp.Value}";
            }

            snaping_timer += dev_snap.TASK_PERIOD;
            if (snaping_timer >= snaping_ms) // 结束
            {
                string res = GetSnapingResult();
                snaping_ms = -1;
                snaping_timer = 0;
                return res;
            }
            return "";
        }
        public void StartSnaping(int ms)
        {
            if (snaping_ms >= 0) return;
            if (mac_value.Length == 0) mac_value += $"快照[{ms}]; ";
            else mac_value = mac_value + RecordDelay() + $"\n快照[{ms}]; ";
            snaping_ms = ms;
            snaping_timer = 0;
            snaping_dict.Clear();
            //mac_value += DispPanel.Snap();
            //mac_value += HWPanel.Snap();
            //mac_value += "\n";
            //return true;
        }


        public int cmds_idx { get; set; } = -1;         // 当前执行的命令
        private string[]? cmds = null;                  // 执行的宏命令列表
        private string[]? exps = null;                  // 执行后预期结果列表
        private int exps_idx = -1;                      // 当前对比的预期结果
        private StringBuilder results = new(1024);
        private int excuting_state = 0;
        public bool StartExcuting()
        {
            if (cmds_idx >= 0)      // 已经在宏执行状态
                return false;
            if (mac_value.Length <= 4) return false; // 保护一下
            string[] tmps = mac_value.Split('\n', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries);
            if (tmps.Length != 2) return false;

            cmds = tmps[0].Split(';', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries);
            if (cmds.Length <= 1 || cmds[0] != "记录") return false;
            cmds_idx = 1;
            exps = tmps[1].Split(';', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries);
            if (exps.Length <= 1 || exps[0].IndexOf("快照") == -1) return false;
            exps_idx = 1;
            results.Clear();
            excuting_state = 0;
            cmd_delay_param = 0;
            key = 0;
            return true;
        }
        // 解析字符串中的命令和参数
        private (string, string) ParseCmdStr(string cmd_str)
        {
            // 解析本次命令和参数
            string[] tmp = cmd_str.Split('[', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries);
            string cmd = tmp[0];
            string param = "";
            if (tmp.Length > 1)
                param = tmp[1].Trim(']');
            return (cmd, param);
        }

        // 循环执行宏动作
        public string Excuting()
        {
            /*
            if (cmds_idx < 0)           // 不在宏执行状态
                return "没有宏命令";
            if (cmds == null || cmds.Length == 0)    // 没有宏命令，执行完毕
                return "没有宏命令";
            string cmd, param;
            while (cmds_idx < cmds.Length)
            {
                // 分离本次命令和参数
                (cmd, param) = ParseCmdStr(cmds[cmds_idx]);

                switch (cmd)
                {
                    case "延时":
                        if (cmd_delay_param == 0)
                        {
                            cmd_delay_param = int.Parse(param);
                            return "执行中";
                        }
                        else
                            cmd_delay_param -= 50;
                        dev_snap.key_val = key;         // 保持key状态
                        if (cmd_delay_param > 0)
                            return "执行中";
                        else    // 延时结束，步进到下一个命令
                        {
                            cmd_delay_param = 0;
                            cmds_idx++;
                            break;
                        }
                    case "按下":
                        {
                            int i = 0;
                            for (; i < dev_snap.keys_def.Length && param != dev_snap.keys_def[i]; i++) ;
                            key |= (byte)(1 << i);
                            dev_snap.key_val = key;
                            cmds_idx++;
                            break;
                        }
                    case "松开":
                        {
                            int i = 0;
                            for (; i < dev_snap.keys_def.Length && param != dev_snap.keys_def[i]; i++) ;
                            key &= (byte)(~(1 << i));
                            dev_snap.key_val = key;
                            cmds_idx++;
                            break;
                        }
                    case "门1":
                        {
                            emu_cfg.door1 = (param == "开");
                            //dev_snap.WriteGPIO(dev_snap.gpio_tb.det_door1, ((param == "开")? false:true));
                            cmds_idx++;
                            break;
                        }
                    default:
                        cmds_idx++;
                        break;
                }
            }
            if (excuting_state == 0) excuting_state++;
            // 执行完毕, 如果有预期结果，启动获取执行结果
            if (excuting_state == 1 && snaping_ms == -1 && exps.Length > 1)
            {
                // 分离snap命令和参数
                (cmd, param) = ParseCmdStr(exps[0]);
                if (cmd == "快照")
                    StartSnaping(Int32.Parse(param));
                excuting_state++;
            }
            // 抓取执行结果
            string snaping_result = "";
            if (excuting_state == 2 && snaping_ms >= 0)      // snaping 状态中, 停止记录宏
            {
                snaping_result = Snaping();
                if (snaping_result.Length > 0)
                    excuting_state++;
                else
                    return "执行中";
            }
            // 检查
            if (excuting_state == 3 && snaping_result.Length > 0)
            {
                Check(snaping_result);
            }

            // 执行完毕, 清理返回
            cmds_idx = -1;
            cmds = null;
            */
            return "结束";
        }

        private bool Check(string snap_str)
        {
            results.Clear();
            exps.SequenceEqual(exps);
            if (exps == null || exps.Length <= 1)    // 没有宏命令，执行完毕
                return true;
            while (exps_idx < exps.Length)
            {
                // 分离本次命令和参数
                (string cmd, string param) = ParseCmdStr(exps[exps_idx]);
                if(cmd == "数显")
                {
                    string[] items = param.Split(',', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries);
                    HashSet<string> list1 = new();
                    for (int i = 0; i < items.Length; i++) list1.Add(items[i]);
                    // 抓出宏记录的快照中的对应参数数据
                    MatchCollection matches = Regex.Matches(mac_value, @"数显\[(.*?)\]");
                    string old_str = matches[0].Groups[1].Value;
                    items = old_str.Split(',', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries);
                    HashSet<string> list2 = new();
                    for (int i = 0; i < items.Length; i++) list2.Add(items[i]);
                    // 比较
                    if(!list1.SetEquals(list2))
                        results.AppendFormat("{0}; ", exps[exps_idx]);
                }
                else
                {
                    if (snap_str.IndexOf(exps[exps_idx]) == -1)
                        results.AppendFormat("{0}; ", exps[exps_idx]);
                }
                exps_idx++;
            }
            // 执行完毕, 清理返回
            exps_idx = -1;
            exps = null;
            if (results.Length == 0)
            {
                results.Append("无异常");
                return true;
            }
            else return false;
        }

        public string GetCheckedResults()
        {
            return results.ToString();
        }


        // 同步设备到snap的状态
        public void Sync()
        {
        }
    }
}
